/**

 @Name : jQuery 日历展示插件
 @Author: mtr
 @since 2021-08-12

 */

;(function ($, window, document, undefined) {
    'use strict';

    var util = {
        // 创建元素
        elem: function (elemName, attr) {
            var elem = document.createElement(elemName);
            $.each(attr || {}, function (key, value) {
                elem.setAttribute(key, value);
            });
            return $(elem);
        },
        // 得到某月的最后一天
        getEndDay: function (month, year) {
            var thisDate = new Date();
            //设置日期为下个月的第一天
            thisDate.setFullYear(
                year || thisDate.getFullYear()
                , month || (thisDate.getMonth() + 1)
                , 1);
            //减去一天，得到当前月最后一天
            return new Date(thisDate.getTime() - 1000 * 60 * 60 * 24).getDate();
        },
        // 数字前置补零
        digit: function (num, length) {
            var str = '';
            num = String(num);
            length = length || 2;
            for (var i = num.length; i < length; i++) {
                str += '0';
            }
            return num < Math.pow(10, length) ? str + (num | 0) : num;
        },
        // 获取日期对象
        getDateObj: function (date) {
            var dateObj = {};
            date = date || new Date();
            dateObj.year = date.getFullYear();
            dateObj.month = date.getMonth() + 1;
            dateObj.yearMonth = dateObj.year + "-" + util.digit(dateObj.month, 2);
            dateObj.day = date.getDate();
            dateObj.week = date.getDay();
            dateObj.date = dateObj.yearMonth + "-" + util.digit(dateObj.day, 2);
            dateObj.time = date.getTime();
            return dateObj;
        },
        // 获取当月的日期列表
        getDateListByMonth: function (month, year) {
            var dateList = [];
            var endDay = util.getEndDay(month, year);
            for (let day = 1; day <= endDay; day++) {
                var date = year + "-" + util.digit(month, 2) + "-" + util.digit(day, 2);
                var dateObj = util.getDateObj(new Date(date));
                if (day === 1 && dateObj.week > 0) {
                    // 如果第一天不是周天 则补全至周天
                    for (let w = 0; w < dateObj.week; w++) {
                        dateList.push({
                            week: w
                        });
                    }
                }
                dateList.push(dateObj);
                if (day === endDay && dateObj.week < 6) {
                    // 如果最后一天不是周六 则补全至周六
                    for (let w = dateObj.week + 1; w < 7; w++) {
                        dateList.push({
                            week: w
                        });
                    }
                }
            }
            return dateList;
        },
    };

    var nowDate = new Date(),
        // 默认开始时间 现在
        currentDate = util.getDateObj(nowDate);

    // 常量
    const CALENDAR_BASE_CLASS = "td-calendar-wrap"; // 根标签类名

    var TdCalendar = function (elem, config) {
        this.config = config;
        // console.log("startConfig", config);
        this.$elem = $(elem);
        this.$elem_source = this.$elem.clone();

        this.$elem.addClass(CALENDAR_BASE_CLASS);
        this.init();
    };

    // 默认配置
    TdCalendar.DEFAULT_CONFIG = {
        // 当前显示的年月
        currentYearMonth: currentDate.yearMonth,
        // 上一月/下一月按钮是否显示
        prevAndNextMonthShow: true,
        // 切换月份事件
        // yearMonthStr: 切换后的年月
        switchMonthEvent: function (yearMonthStr) {
        },
        // 日期列表
        dataList: [],
        // 日期框最小高度
        dataMinHeight: "50px",
        // 日期框最大高度
        dataMaxHeight: "500px",
        // 绘制日期格内容时的回调函数
        // dateData: 当前日期传入数据
        // dayData: 当前日期数据
        // $dateContent: 当前日期内容区域jQuery对象
        // 返回值， 如果返回了内容 则会把返回的内容添加到$dateContent中
        drawDateContentEvent: function (dateData, dayData, $dateContent) {
        },
        // 是否为存在dateContent才调用 为false时，全部日期渲染都会调用
        drawDateContentIfExist: true,
        // 日期内容区域的最大高度 不包含表示星期的行 如果设置了，超过高度就可以滚动
        dateContentMaxHeight: "",
        // 法定节假日信息
        statutoryHoliday: [],
        // 是否显示选中样式
        activeFlag: false,
        // 绘制头部内容时的回调函数
        // yearMonthStr: 当前月
        // $dateContent: 头部内容区域jQuery对象
        drawHeaderContentEvent: function (yearMonthStr, $headerContent) {
        },
        // 头部年月显示的对齐方式 left center right
        headerYearMonthAlign: "center",
        // 按键事件是否全局生效
        keyUpEventGlobal: false,
        // 日期框点击样式
        // dateData: 当前日期传入数据
        // dayData: 当前日期数据
        // $dateElem: 当前日期区域jQuery对象
        // e：event
        clickEvent: function (dateData, dayData, $dateElem, e) {
        }
    };

    // 默认日期配置
    TdCalendar.DEFAULT_DATE_CONFIG = {
        // 对应的日期 2021-08-11
        date: currentDate.date,
        // 日期描述 如：七夕，休 等
        dateTips: "",
        // 是否显示选中样式
        activeFlag: false
    };

    // 插件初始化
    TdCalendar.prototype.init = function () {
        this.initConfig();
        this.initTagStructure();
        this.initCalendarInfo();
        this.initKeyUpEvent();
    };

    // 初始化配置
    TdCalendar.prototype.initConfig = function () {
        // 设置当前年月
        let yearMonth = this.config.currentYearMonth.split('-');
        this.currentYear = yearMonth[0];
        this.currentMonth = yearMonth[1];
        this.dataContentMap = {};
        this.statutoryHolidayMap = {};
        this.initDataAndHoliday(this.config.dataList, this.config.statutoryHoliday);
    };

    // 初始化数据和节假日
    TdCalendar.prototype.initDataAndHoliday = function (dataList, statutoryHoliday) {
        // 解析日期数据
        var dataContentMap = this.dataContentMap;
        if (dataList && dataList.length > 0) {
            dataList.forEach(function (sourceData) {
                let data = $.extend({}, TdCalendar.DEFAULT_DATE_CONFIG, typeof sourceData === 'object' && sourceData);
                let dataContent = dataContentMap[data.date];
                if (dataContent) {
                    dataContent.dataList.push(sourceData);
                } else {
                    data.dataList = [sourceData];
                    dataContentMap[data.date] = data;
                }
            });
        }
        // 解析法定节假日数据
        var statutoryHolidayMap = this.statutoryHolidayMap;
        if (statutoryHoliday && statutoryHoliday.length > 0) {
            statutoryHoliday.forEach(function (data) {
                statutoryHolidayMap[data.date] = data;
            });
        }
    };


    // 点击上一月时间
    TdCalendar.prototype.eventPrevMonth = function () {
        if (this.currentMonth === '01') {
            this.currentMonth = '12';
            this.currentYear = parseInt(this.currentYear) - 1 + '';
        } else {
            this.currentMonth = util.digit(parseInt(this.currentMonth) - 1);
        }
        this.initCalendarInfo();
        if (typeof this.config.switchMonthEvent == 'function') {
            this.config.switchMonthEvent(this.currentYear + "-" + this.currentMonth);
        }
    };
    // 点击下一月时间
    TdCalendar.prototype.eventNextMonth = function () {
        if (this.currentMonth === '12') {
            this.currentMonth = '01';
            this.currentYear = parseInt(this.currentYear) + 1 + '';
        } else {
            this.currentMonth = util.digit(parseInt(this.currentMonth) + 1);
        }
        this.initCalendarInfo();
        if (typeof this.config.switchMonthEvent == 'function') {
            this.config.switchMonthEvent(this.currentYear + "-" + this.currentMonth);
        }
    };

    // 初始化标签结构
    TdCalendar.prototype.initTagStructure = function () {
        this.$area = $('<div class="td-calendar-area"></div>');
        this.$elem.append(this.$area);
        this.$header = $('<div class="td-calendar-header"></div>');
        this.$yearMonth = $([
            '<div class="td-calendar-yearMonth">',
            '    <span class="prev-month" style="display:none;"><</span>',
            '    <div class="year-month-txt">',
            '        <span class="year">年</span>',
            '        <span class="month">月</span>',
            '    </div>',
            '    <span class="next-month" style="display:none;">></span>',
            '</div>',
        ].join(''));
        if (this.config.headerYearMonthAlign) {
            this.$yearMonth.css("justify-content", this.config.headerYearMonthAlign);
        }
        this.$header.append(this.$yearMonth);
        this.$area.append(this.$header);
        this.$year = this.$yearMonth.find(".year");
        this.$month = this.$yearMonth.find(".month");
        this.$prevMonth = this.$yearMonth.find(".prev-month");
        var that = this;
        // 设置点击上一页事件
        this.$prevMonth.click(function () {
            that.eventPrevMonth()
        });
        // 设置点击下一页事件
        this.$nextMonth = this.$yearMonth.find(".next-month");
        this.$nextMonth.click(function () {
            that.eventNextMonth()
        });
        if (this.config.prevAndNextMonthShow) {
            // 显示上一页/下一页
            this.$prevMonth.show();
            this.$nextMonth.show();
        }
        this.$center = $([
            '<div class="td-calendar-content">',
            '    <div class="td-calendar-weekList">',
            '        <span class="week-item week-restDay">日</span>',
            '        <span class="week-item">一</span>',
            '        <span class="week-item">二</span>',
            '        <span class="week-item">三</span>',
            '        <span class="week-item">四</span>',
            '        <span class="week-item">五</span>',
            '        <span class="week-item week-restDay">六</span>',
            '    </div>',
            '    <div class="td-calendar-date-list-box"></div>',
            '</div>'
        ].join(''));
        this.$area.append(this.$center);
        this.$weekList = this.$center.find(".td-calendar-weekList");
        this.$dayList = this.$center.find(".td-calendar-date-list-box");
        this.setDateContentMaxHeight();

        if (typeof this.config.drawHeaderContentEvent == 'function') {
            // 头部渲染回调事件
            var headerContentDom = this.config.drawHeaderContentEvent(this.currentYear + "-" + this.currentMonth, this.$header);
            if (headerContentDom) {
                this.$header.append(headerContentDom);
            }
        }
    };

    // 设置内容高度
    TdCalendar.prototype.setDateContentMaxHeight = function () {
        if (this.config.dateContentMaxHeight) {
            // 设置日期内容的高度
            this.$dayList.css("max-height", this.config.dateContentMaxHeight);
            // 监听页面高度
            $(window).resize(() => {
                this.$dayList.css("max-height", this.config.dateContentMaxHeight);
            });
        }
    };

    // 初始化回车事件
    TdCalendar.prototype.initKeyUpEvent = function () {
        this.$elem.attr("tabindex", "18");
        (this.config.keyUpEventGlobal ? $("body") : this.$elem).keyup(e => {
            console.log(e.keyCode);
            if(e.keyCode === 37){
                // 左键事件 上月
                this.$prevMonth.click();
            } else if(e.keyCode === 39){
                // 右键事件 下月
                this.$nextMonth.click();
            }
        });
    };

    // 初始化日历信息
    TdCalendar.prototype.initCalendarInfo = function () {
        // 设置当前年月
        this.$year.text(this.currentYear + "年");
        this.$month.text(this.currentMonth + "月");
        // 获取当月所有日期显示
        var dayList = util.getDateListByMonth(parseInt(this.currentMonth), parseInt(this.currentYear));
        this.$dayList.empty();
        var $oneWeekDay = null;
        for (let i = 0; i < dayList.length; i++) {
            if (!$oneWeekDay) {
                $oneWeekDay = $('<ul class="td-calendar-date-list"></ul>');
                this.$dayList.append($oneWeekDay);
            }
            var dayData = dayList[i];
            var dataContent = this.dataContentMap[dayData.date];
            if (dayData.day) {
                var $dateItem = this.create$DateItem(dayData);
                // 设置日期描述
                if (dataContent) {
                    $dateItem.find(".date-tips").html(dataContent.dateTips || '');
                }
                // 鼠标移入选中样式
                if (this.config.activeFlag || (dataContent && dataContent.activeFlag)) {
                    $dateItem.addClass("td-calendar-date-active");
                }
                // 渲染日期内容框
                var $dateContent = $dateItem.find(".td-calendar-date-content");
                // 设置日期框的高度
                if (this.config.dataMinHeight) {
                    $dateContent.css("min-height", this.config.dataMinHeight);
                }
                if (this.config.dataMaxHeight) {
                    $dateContent.css("max-height", this.config.dataMaxHeight);
                }
                if (typeof this.config.drawDateContentEvent == 'function') {
                    // 当配置为全部执行或日期存在时执行渲染
                    if (!this.config.drawDateContentIfExist || dataContent) {
                        var dataContentDom = this.config.drawDateContentEvent(dataContent, dayData, $dateContent);
                        if (dataContentDom) {
                            $dateContent.append(dataContentDom);
                        }
                    }
                }
                if (typeof this.config.clickEvent == 'function') {
                    var that = this;
                    $dateItem.click(function (e) {
                        var dayData = dayList[i];
                        var dataContent = that.dataContentMap[dayData.date];
                        that.config.clickEvent(dataContent, dayData, $(this), e);
                    });
                }
                $oneWeekDay.append($dateItem);
            } else {
                // 没有日期则当前为空
                $oneWeekDay.append('<li class="td-calendar-date-item"></li>');
            }
            if (dayData.week === 6) {
                // 如果到了周六 则重新换一行
                $oneWeekDay = null;
            }
        }
    };

    // 创建日期框
    TdCalendar.prototype.create$DateItem = function (dayData) {
        var $dateItem = $([
            '<li class="td-calendar-date-item">',
            '    <div class="date-info">',
            '        <span class="date">' + util.digit(dayData.day) + '</span>',
            '        <div class="date-remark">',
            // '           <span class="date-sign"></span>',
            '           <span class="date-tips"></span>',
            '        </div>',
            '    </div>',
            '    <div class="td-calendar-date-content">',
            '    </div>',
            '</li>'
        ].join(''));
        var $date = $dateItem.find(".date");
        // var $sign = $dateItem.find(".date-sign");
        // 今天
        if (dayData.date === currentDate.date) {
            $dateItem.addClass("td-calendar-date-today");
            $date.addClass("date-today");
            // $sign.text("今天");
        }
        if (dayData.week === 0 || dayData.week === 6) {
            $dateItem.addClass("td-calendar-date-week");
        }
        var holiday = this.statutoryHolidayMap[dayData.date];
        if (holiday) {
            $dateItem.removeClass("td-calendar-date-week");
            if (holiday.isWork) {
                $dateItem.addClass("td-calendar-date-special");
                // 补班
                // $sign.text("班");
            } else {
                $dateItem.addClass(holiday.isHolidayDay ? "td-calendar-date-festival-day" : "td-calendar-date-festival");
                // 放假
                // $sign.text(holiday.isHolidayDay ? holiday.holidayName : "休");
            }
        }
        return $dateItem;
    };

    // 修改渲染的年月
    TdCalendar.prototype.yearMonth = function (yearMonthStr, dataList, statutoryHoliday) {
        if (typeof yearMonthStr !== 'string' || !/[0-9]{4}-[0|1|2|3][0-9]/g.test(yearMonthStr)) {
            console.error("请输入合理的年月参数，如：2021-08");
            return;
        }
        // 设置当前年月
        let yearMonth = yearMonthStr.split('-');
        this.currentYear = yearMonth[0];
        this.currentMonth = yearMonth[1];
        // 删除当月之前的数据
        for (let i = 1; i <= 31; i++) {
            var day = yearMonthStr + "-" + util.digit(i, 2);
            if (this.dataContentMap.hasOwnProperty(day)) {
                delete this.dataContentMap[day];
            }
        }
        // 重新初始化数据和节假日信息
        this.initDataAndHoliday(dataList, statutoryHoliday);
        // 重新渲染
        this.initCalendarInfo();
    };

    const DATA_KEY = 'td-calendar';

    $.fn.tdCalendar = function (option) {
        var value,
            args = Array.prototype.slice.call(arguments, 1);

        this.each(function () {
            var $this = $(this),
                data = $this.data(DATA_KEY),
                options = $.extend({}, TdCalendar.DEFAULT_CONFIG, typeof option === 'object' && option);

            if (typeof option === 'string') {
                if (!data) {
                    return;
                }
                switch (option) {
                    case "yearMonth":
                        data.yearMonth.apply(data, args);
                        break;
                    case "destroy":
                        $this.removeData(DATA_KEY);
                        $this.html(data.$elem_source.html());
                        break;
                }
            }

            if (!data) {
                $this.data(DATA_KEY, new TdCalendar(this, options));
            }
        });

        return typeof value === 'undefined' ? this : value;
    };

})(jQuery, window, document,);
